package eosgo

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	//"reflect"

	eos "github.com/yekai1003/eos-go"
)

var eosapi *eos.API
var adminpermisson eos.PermissionLevel
var txOpts *eos.TxOptions

// 该文件初始化自动运行
func init() {
	ReInit()
}

func ReInit() {

	// 1. 连接到节点
	eosapi = eos.New("http://127.0.0.1:8888")

	//2. 设置调用权限
	adminpermisson = eos.PermissionLevel{
		Actor:      eos.AN("admin"),
		Permission: eos.PN("active"),
	}

	//3. 私钥导入
	keyBag := &eos.KeyBag{}
	keyBag.ImportPrivateKey(context.Background(), "5HsSt8BTrUkGPBmB7tMbBFvdA3TczUbaZMtH7buceV5H29FXMqc")

	eosapi.SetSigner(keyBag)

	//4. 填写交易附选项
	txOpts = &eos.TxOptions{}
	if err := txOpts.FillFromChain(context.Background(), eosapi); err != nil {
		panic(fmt.Errorf("filling tx opts: %w", err))
	}
}

//bool login(name admin, name sname, string password);

type LoginReq struct {
	AdminName eos.Name `json:"admin"`
	UserName  eos.Name `json:"sname"`
	Password  string   `json:"password"`
}

func Login(name, pass string) (bool, error) {

	// 构建Action数据
	data := LoginReq{eos.Name("admin"), eos.Name(name), pass}
	actData := eos.NewActionData(data)

	//组织action
	act := eos.Action{
		Account:       eos.AN("userauth"),
		Name:          eos.ActN("login"),
		Authorization: []eos.PermissionLevel{adminpermisson},
		ActionData:    actData,
	}

	response, err := eosapi.SignPushActionsWithOpts(context.Background(), []*eos.Action{&act}, txOpts)
	if err != nil {
		log.Panic("failed tp SignPushActionsWithOpts ", err)
	}
	if response != nil {
		fmt.Printf("-------------%+v\n", response)
		data := fmt.Sprintf("%v", response.Processed.ActionTraces[0].RetValData)
		if data == "true" {
			return true, nil
		}
		//fmt.Println(response.Processed.ActionTraces[0].RetValData, reflect.TypeOf(response.Processed.ActionTraces[0].RetValData))
	}

	return false, nil
}

func Register(name, pass string) error {
	// 构建Action数据
	//void userreg(name admin, name sname, string password);
	data := LoginReq{eos.Name("admin"), eos.Name(name), pass}
	actData := eos.NewActionData(data)

	//组织action
	act := eos.Action{
		Account:       eos.AN("userauth"),
		Name:          eos.ActN("userreg"),
		Authorization: []eos.PermissionLevel{adminpermisson},
		ActionData:    actData,
	}

	_, err := eosapi.SignPushActionsWithOpts(context.Background(), []*eos.Action{&act}, txOpts)
	if err != nil {
		log.Println("failed tp SignPushActionsWithOpts ", err)
		return err
	}

	return nil
}

// 空投服务
//void yktransfer(name admin, name symbol,
//                name from, name to, uint64_t amount);

type TransferReq struct {
	AdminName eos.Name `json:"admin"`
	Symbol    eos.Name `json:"symbol"`
	FromName  eos.Name `json:"from"`
	ToName    eos.Name `json:"to"`
	Amount    uint64   `json:"amount"`
}

func Mint(toname string, amount uint64) error {
	// 构建Action数据
	data := TransferReq{eos.Name("admin"), eos.Name("ykc"), eos.Name("ykc"), eos.Name(toname), amount}
	actData := eos.NewActionData(data)

	//组织action
	act := eos.Action{
		Account:       eos.AN("yktoken"),
		Name:          eos.ActN("yktransfer"),
		Authorization: []eos.PermissionLevel{adminpermisson},
		ActionData:    actData,
	}

	_, err := eosapi.SignPushActionsWithOpts(context.Background(), []*eos.Action{&act}, txOpts)
	if err != nil {
		log.Println("failed tp SignPushActionsWithOpts ", err)
		return err
	}

	return nil
}

//void issuetask(name admin, name issuer, string desc, uint64_t bonus);
type IssueTaskReq struct {
	AdminName eos.Name `json:"admin"`
	Issuer    eos.Name `json:"issuer"`
	Desc      string   `json:"desc"`
	Bonus     uint64   `json:"bonus"`
}

func Issue(issuer, desc string, amount uint64) error {
	// 构建Action数据
	data := IssueTaskReq{eos.Name("admin"), eos.Name(issuer), desc, amount}
	actData := eos.NewActionData(data)

	//组织action
	act := eos.Action{
		Account:       eos.AN("yktask"),
		Name:          eos.ActN("issuetask"),
		Authorization: []eos.PermissionLevel{adminpermisson},
		ActionData:    actData,
	}

	_, err := eosapi.SignPushActionsWithOpts(context.Background(), []*eos.Action{&act}, txOpts)
	if err != nil {
		log.Println("failed tp SignPushActionsWithOpts ", err)
		return err
	}

	return nil
}

//{"taskid":0,"issuer":"yekai","hunter":"none","status":0,"desc":"write code",
//"comment":"","tasktime":"2021-12-06T02:56:06","bonus":200}
// eos 返回类型
type EosTask struct {
	TaskID  uint64 `json:"taskid"`
	Issuer  string `json:"issuer"`
	Hunter  string `json:"hunter"`
	Comment string `json:"comment"`
	Status  uint8  `json:"status"`
	Desc    string `json:"desc"`
	Bonus   uint64 `json:"bonus"`
}

// 前端请求类型
type TaskIssueReq struct {
	TaskID  string `json:"task_id"`
	Issuer  string `json:"issuer"`
	Hunter  string `json:"task_user"`
	Comment string `json:"comment"`
	Status  uint8  `json:"task_status"`
	Desc    string `json:"task_name"`
	Bonus   uint64 `json:"bonus"`
}

func QueryTask(begin, end int) ([]TaskIssueReq, error) {
	var tasks []EosTask
	var itasks []TaskIssueReq
	params := eos.GetTableRowsRequest{}
	params.Code = "yktask"
	params.Scope = "admin"
	params.Table = "tasks"
	params.JSON = true
	params.LowerBound = fmt.Sprintf("%d", begin)
	params.UpperBound = fmt.Sprintf("%d", end)

	//2. 获取表数据
	resprows, err := eosapi.GetTableRows(context.Background(), params)
	if err != nil {
		log.Println("failed to GetTableRows ", err)
		return itasks, err
	}
	//fmt.Printf("getrows:%+s\n", resprows.Rows)
	err = json.Unmarshal(resprows.Rows, &tasks)
	if err != nil {
		log.Println("failed Unmarshal rows ", err)
		return itasks, err
	}
	fmt.Printf("tasks:%+v\n", tasks)
	//组织一下数据
	var task TaskIssueReq
	for _, v := range tasks {
		task.TaskID = fmt.Sprintf("%d", v.TaskID)
		task.Bonus = v.Bonus
		task.Comment = v.Comment
		task.Desc = v.Desc
		task.Hunter = v.Hunter
		task.Status = v.Status
		task.Issuer = v.Issuer

		itasks = append(itasks, task)
	}

	return itasks, nil
}

//void taketask(name admin, uint64_t taskid, name hunter);
//void committask(name admin, uint64_t taskid, name hunter);

type HunterReq struct {
	AdminName eos.Name `json:"admin"`
	TaskID    uint64   `json:"taskid"`
	Hunter    eos.Name `json:"hunter"`
}

func hunterTask(hunter string, taskid uint64, action string) error {
	// 构建Action数据
	data := HunterReq{eos.Name("admin"), taskid, eos.Name(hunter)}
	actData := eos.NewActionData(data)

	//组织action
	act := eos.Action{
		Account:       eos.AN("yktask"),
		Name:          eos.ActN(action),
		Authorization: []eos.PermissionLevel{adminpermisson},
		ActionData:    actData,
	}

	_, err := eosapi.SignPushActionsWithOpts(context.Background(), []*eos.Action{&act}, txOpts)
	if err != nil {
		log.Println("failed tp SignPushActionsWithOpts ", err)
		return err
	}

	return nil
}

//void confirmtask(name admin, uint64_t taskid, name issuer,
//uint8_t status, string comment);
type IssuerReq struct {
	AdminName eos.Name `json:"admin"`
	TaskID    uint64   `json:"taskid"`
	Issuer    eos.Name `json:"issuer"`
	Status    uint8    `json:"status"`
	Comment   string   `json:"comment"`
}

func issuerTask(issuer string, taskid uint64, action string, status uint8, comment string) error {
	// 构建Action数据
	data := IssuerReq{eos.Name("admin"), taskid, eos.Name(issuer), status, comment}
	actData := eos.NewActionData(data)

	//组织action
	act := eos.Action{
		Account:       eos.AN("yktask"),
		Name:          eos.ActN(action),
		Authorization: []eos.PermissionLevel{adminpermisson},
		ActionData:    actData,
	}

	_, err := eosapi.SignPushActionsWithOpts(context.Background(), []*eos.Action{&act}, txOpts)
	if err != nil {
		log.Println("failed tp SignPushActionsWithOpts ", err)
		return err
	}

	return nil
}

func UpdateTask(from string, taskid uint64, status uint8, comment string) error {
	if status == 1 {
		// take task
		return hunterTask(from, taskid, "taketask")
	}
	if status == 2 {
		// commit
		return hunterTask(from, taskid, "committask")
	}
	if status == 3 || status == 4 {
		if status != 3 {
			status = 1 //退回
		}
		// 添加发送积分的转账
		return issuerTask(from, taskid, "confirmtask", status, comment)
	}

	return nil
}

type BalanceReq struct {
	AdminName eos.Name `json:"admin"`
	Symbol    eos.Name `json:"symbol"`
	Account   eos.Name `json:"who"`
}

func BalanceOf(name string) (uint64, error) {

	// 构建Action数据
	//uint64_t ykbalanceof(name admin, name symbol, name who);
	data := BalanceReq{eos.Name("admin"), eos.Name("ykc"), eos.Name(name)}
	actData := eos.NewActionData(data)

	//组织action
	act := eos.Action{
		Account:       eos.AN("yktoken"),
		Name:          eos.ActN("ykbalanceof"),
		Authorization: []eos.PermissionLevel{adminpermisson},
		ActionData:    actData,
	}

	response, err := eosapi.SignPushActionsWithOpts(context.Background(), []*eos.Action{&act}, txOpts)
	if err != nil {
		log.Println("failed tp SignPushActionsWithOpts ", err)
		return 0, err
	}
	if response != nil {
		//fmt.Printf("-------------%+v\n", response)
		//fmt.Printf("%v\n", response.Processed.ActionTraces[0].RetValData)
		return uint64(response.Processed.ActionTraces[0].RetValData.(float64)), nil
		//fmt.Println(response.Processed.ActionTraces[0].RetValData, reflect.TypeOf(response.Processed.ActionTraces[0].RetValData))
	}

	return 0, nil
}
